package com.hls.zfbai.core.utils;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.symmetric.SM4;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hls.zfbai.modules.business.entity.ZfbAiBase;
import com.hls.zfbai.modules.business.entity.ZfbAiData;
import com.hls.zfbai.modules.business.entity.ZfbAiParam;
import com.hls.zfbai.modules.common.util.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;

import java.util.*;

@Slf4j
public class SM2AndSM4Utils {
    // 支付宝AI接口请求地址
    public static final String REQ_URL = "http://192.168.20.203:18087/api/his/data/transmission";
    // 医疗机构的18位统⼀社会信⽤代码
    public static final String MED_ORG_CODE = "123700004955424336";
    // 区域平台归属单位的18位统⼀社会信⽤代码
    public static final String PLATFORM_CODE = "";
//    public static final String PLATFORM_CODE = CommonUtils.getGyXtcs("1", "ZFBAI_PLATFORM_CODE", "123700004955424336", "区域平台归属单位的18位统一社会信用代码");
    // sm4秘钥
    public static final String SM4_KEY = "d200fd3918bdc7041a1706fc249b4345";
    // sm2公钥
    public static final String SM2_PUBLIC_KEY = "048ac97ab82a138e95084a9f0fc465f322cb8c2a979deb5c98237d37b273c89084ee98af103c60e87aaaaf9a5db73999148cea9ec57ddb199f82aab0001e780145";
    // sm2私钥
    public static final String SM2_PRIVATE_KEY = "23b43c9c7ae57c56ccb3d9400dc7b5059e4b273ab877633bf3197f9374e0261b";
    /**
     * 私钥返回值常量
     */
    public static final String KEY_PRIVATE_KEY = "privateKey";
    public static final String KEY_PUBLIC_KEY = "publicKey";
    public static void main(String[] args) throws Exception {
                System.out.println("--------------------------------↓sm4加密↓--------------------------------");
                        // 请求对象json
                        String content = "{\n" +
                                "\"cfbh\":\"2022082066316802\",\n" +
                                "\"loadTime\":\"20220101120809\"}\n" +
                                "}";
        System.out.println("sm4加密前字符串：" + content);
        // 加密
        String encryptBody = SM2AndSM4Utils.sm4EncryptBase64(content, SM4_KEY);
        System.out.println("sm4加密后字符串：" + encryptBody);
        // 解密

        String decryptBody = SM2AndSM4Utils.sm4DecryptBase64(encryptBody, SM4_KEY);
        System.out.println("sm4解密后字符串：" + decryptBody);
    }
    /**
     * ⽣成SM2公私钥
     *
     * @return
     */
    public static JSONObject generateSm2Key() {
        SM2 sm2 = new SM2();
        ECPublicKey publicKey = (ECPublicKey) sm2.getPublicKey();
        ECPrivateKey privateKey = (ECPrivateKey) sm2.getPrivateKey();
        // 获取公钥
        byte[] publicKeyBytes = publicKey.getQ().getEncoded(false);
        String publicKeyHex = HexUtil.encodeHexStr(publicKeyBytes);
        // 获取64位私钥
        String privateKeyHex = privateKey.getD().toString(16);
        // BigInteger转成16进制时，不⼀定⻓度为64，如果私钥⻓度⼩于64，则在前⽅补0
        StringBuilder privateKey64 = new StringBuilder(privateKeyHex);
        while (privateKey64.length() < 64) {
            privateKey64.insert(0, "0");
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(KEY_PUBLIC_KEY, publicKeyHex);
        jsonObject.put(KEY_PRIVATE_KEY, privateKey64.toString());
        return jsonObject;
    }
    /**
     * SM2私钥签名
     *
     * @param privateKey 私钥
     * @param content 待签名内容
     * @return 签名值
     */
    public static String sm2Sign(String privateKey, String content) {
        SM2 sm2 = new SM2(privateKey, null);
        return sm2.signHex(HexUtil.encodeHexStr(content));
    }
    /**
     * SM2公钥验签
     * @param publicKey 公钥
     * @param content 原始内容
     * @param sign 签名
     * @return 验签结果
     */
    public static boolean sm2Verify(String publicKey, String content, String sign) {
        SM2 sm2 = new SM2(null, publicKey);
        return sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
    }
    /**
     * SM2公钥加密
     * @param content 原⽂
     * @param publicKey SM2公钥
     * @return
     */
    public static String sm2EncryptBase64(String content, String publicKey) {
        SM2 sm2 = new SM2(null, publicKey);
        return sm2.encryptBase64(content, KeyType.PublicKey);
    }
    /**
     * SM2私钥解密
     *
     * @param encryptStr SM2加密字符串
     * @param privateKey SM2私钥
     * @return
     */
    public static String sm2DecryptBase64(String encryptStr, String privateKey) {
        SM2 sm2 = new SM2(privateKey, null);
        return StrUtil.utf8Str(sm2.decrypt(encryptStr, KeyType.PrivateKey
        ));
    }
    /**
     * sm4密钥⽣成
     *
     * @return sm4密钥
     */
    public static String generateSm4Key() {
        SM4 sm4 = SmUtil.sm4();
        byte[] encoded = sm4.getSecretKey().getEncoded();
        return HexUtil.encodeHexStr(encoded);
    }

    /**
     * SM4加密
     *
     * @param content 原⽂
     * @param key SM4秘钥
     * @return
     */
    public static String sm4EncryptBase64(String content, String key) {
        byte[] sm4KeyByte = HexUtil.decodeHex(key);
        String encryptBody = SmUtil.sm4(sm4KeyByte).encryptHex(content);
        return encryptBody;
    }
    /**
     * SM4解密
     *
     * @param content SM4加密字符串
     * @param key SM4秘钥
     * @return
     */
    public static String sm4DecryptBase64(String content, String key) {
        byte[] sm4KeyByte = HexUtil.decodeHex(key);
        String decryptBody = SmUtil.sm4(sm4KeyByte).decryptStr(content);
        return decryptBody;
    }
    /**
     * ⽣成预签名字符串
     *
     * @param header
     * @param sm4Key
     * @return
     */
    public static String buildPreSignature(Map<String, Object> header, String sm4Key) {
        if (null == header || StringUtils.isBlank(sm4Key)) {
            return null;
        }
        List<String> keys = new ArrayList<>(header.keySet());
        Collections.sort(keys); // 按ASCII升序排序
        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            Object value = header.get(key);
            // 处理null和不同类型值
            String valueStr = (value != null) ? value.toString() : "";
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(key).append("=").append(valueStr);
        }
        return sb.toString() + "&" + sm4Key;
    }

    public static String buildSignature(Map<String, Object> header) {
        // 预签名字符串
        String preSignature = buildPreSignature(header, SM4_KEY);
        log.info("预签名字符串：{}", preSignature);
        // 签名 （sm2私钥,预签名内容）
        String signature = sm2Sign(SM2_PRIVATE_KEY, preSignature);
        header.put("signature", signature);
        log.info("signature：{}", signature);
        return signature;
    }

    /**
     * 构建支付宝AI参数
     * @return
     */
    public static ZfbAiParam buildZfbAiParam(ZfbAiBase zfbAiBase, Map<String, Object> header) {
        ZfbAiParam zfbAiParam = new ZfbAiParam();
        // 毫秒时间戳
        Long timeStamp = System.currentTimeMillis();
        String param = "";
        String encrypt = "";
        header.put("tradeCode", zfbAiBase.getTradeCode());
        header.put("datasetCode", zfbAiBase.getDatasetCode());
        header.put("requestId", UUID.randomUUID().toString());
//        header.put("platformCode", PLATFORM_CODE);
        header.put("medOrgCode", MED_ORG_CODE);
        header.put("medHosCode", zfbAiBase.getMedHosCode());
        header.put("timestamp", timeStamp);
        //生成签名，放header
        buildSignature(header);
        log.info("header={}", header);
        //JSON转字符串，然后加密
        param = JSON.toJSONString(zfbAiBase);
        log.info("param={}", param);
        encrypt = sm4EncryptBase64(param, SM4_KEY);
        log.info("encrypt={}", encrypt);
        zfbAiParam.setRequestBiz(encrypt);
        return zfbAiParam;
    }

    /**
     * 构建支付宝AI接口出参
     * @param rsp
     * @return
     */
    public static ZfbAiData buildZfbAiData(String rsp) {
        log.info("rsp={}", rsp);
        ZfbAiData zfbAiData = JSON.parseObject(rsp, ZfbAiData.class);
        String responseBiz = "";
        if(!Objects.isNull(zfbAiData)) {
            responseBiz = zfbAiData.getResponseBiz();
            if(StringUtils.isNotBlank(responseBiz)) {
                log.info("解密前responseBiz={}", responseBiz);
                responseBiz = sm4DecryptBase64(responseBiz, SM4_KEY);
                log.info("解密后responseBiz={}", responseBiz);
                zfbAiData.setResponseBiz(responseBiz);
            }
        }

        return zfbAiData;
    }
}